-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] feat: capture transient values in loop block for closures #1585
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1585 +/- ##
===========================================
- Coverage 55.87% 44.75% -11.13%
===========================================
Files 430 438 +8
Lines 65618 67250 +1632
===========================================
- Hits 36667 30100 -6567
- Misses 26083 34637 +8554
+ Partials 2868 2513 -355 ☔ View full report in Codecov by Sentry. |
@@ -5,6 +5,7 @@ func (m *Machine) doOpDefine() { | |||
// Define each value evaluated for Lhs. | |||
// NOTE: PopValues() returns a slice in | |||
// forward order, not the usual reverse. | |||
// m.PopValue() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete?
@ltzmaxwell amazing! 🤩 Thanks as always for tackling these difficult VM issues. Some things I really like about this:
I spent quite a bit of time reviewing your solution, as well as time trying to understand both the problem a bit more. After thinking about this, I arrived at a related but different way to solve the problem using fewer abstractions. Do you think that you could give it a look? Perhaps there is a combined solution that would work well; the code you wrote here certainly made it easier for me to commit my own thoughts to code. https://github.com/deelawn/gno/pull/3/files Also, I was thinking about how a similar issue might arise that doesn't use explicit loops. Consider the following example: package main
func main() {
var y, counter int
var f []func()
defer func() {
for _, ff := range f {
ff()
}
}()
LABEL:
if counter == 5 {
return
}
x := y
f = append(f, func() { println(x) })
y++
counter++
goto LABEL
}
// Output:
// 0
// 1
// 2
// 3
// 4 The solution you've presented here does not account for this scenario. How easy do you think it would be to incorporate it? I'm currently not set on either solution; there may be an even better way than both of us have thought of. I'm hoping some others can post their thoughts here as well, so let me know what you think 😄 |
Just a status update: @jaekwon discussed with maxwell for an alternative approach, which fixes this issue in Preprocessing. @ltzmaxwell, please do ping us for a second review when done! |
Make it draft until done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: your result doesn't match Go's output: https://go.dev/play/p/pbx4N-F4W89
house keeping. |
this is a fix to #1135 .
As discussed in #1135, the go behaviour (expected) should is:
while gno behavior:
The reason for this is the funcLit inside loop block is not capturing every transient values of
v
as the loop went on, It only keeps a reference to it. when this funcLit is in execution, the value of v is3
, so the result will always be 303.This PR provides a solution to capture the transient state as the loop went on, and use these values when the closure is in execution.
The work flow is:
fn
(the closure) is in execution, using [1, 2, 3] to update the context block(in whichv
== 3) to be 1, 2, 3 , and get the expected results.Here are some examples to show in detail:
loopVar
. It's a design decision if we want this.x
the var declared outside of the for block, I'd like to leave it for discussion since it's a design decision.